package com.google.code.gronono.commons.i18n;

import java.io.File;
import java.lang.reflect.Field;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.google.code.gronono.commons.ReflectUtils;
import com.google.code.gronono.commons.net.Protocol;

/**
 * Classe utilitaire permettant de gérer les messages I18N.
 *
 * @author Arnaud BRUNET
 */
@Deprecated
public class I18N {
	/** Logger. */
	private static final Logger logger = Logger.getLogger(I18N.class);

	/** Extension des fichiers jar. */
	//private static final String JAR_EXT = ".jar";
	/** Extension des fichiers class. */
	private static final String CLASS_EXT = ".class";
    /** Séparateur pour les noms de fichiers. */
	private static final char FILE_SEP = '/';
    /** Séparateur pour les noms de packages. */
	private static final char PACKAGE_SEP = '.';

	/**
	 * Cette classe est une classe utilitaire. Son constructeur ne doit jamais être appelé.
	 * @throws UnsupportedOperationException Toujours.
	 */
	private I18N() {
		throw new UnsupportedOperationException();
	}

	/**
	 * Initialise les messages I18N de l'objet spécifié.
	 *
	 * @param object L'objet a initialiser.
	 *  Peut être une classe si tous les champs sont statiques.
	 */
	private static void initializeObject(final Object object) {
		logger.trace("initializeObject(" + object + ")");

		Class<?> clazz = object.getClass();
		// Si l'objet est déjà une classe, la classe est celui-ci
		if (clazz == Class.class) {
			clazz = (Class<?>) object;
		}

		// Vérification de la présence de l'annotation @BundleName
		final BundleName bundle = clazz.getAnnotation(BundleName.class);
		if (bundle != null) {
			final String bundleValue = bundle.value();

			ResourceBundle rb = null;
			try {
				rb = ResourceBundle.getBundle(bundleValue);
			} catch (final MissingResourceException e) {
				logger.warn("Can't find bundle " + bundleValue);
				return;
			}
			for (final Field field : ReflectUtils.getAnnotatedFields(clazz, BundleKey.class)) {
				final BundleKey property = field.getAnnotation(BundleKey.class);
				final String key = property.value();
				Object value = null;
				try {
					if (field.getType() == String.class) {
						value = rb.getString(key);
					} else if ((field.getType() == Integer.class) || (field.getType() == int.class)) {
						value = Integer.parseInt((String) rb.getObject(key));
					} else {
						logger.error("Unsupported type : " + field.getType());
						return;
					}
					ReflectUtils.setField(object, field, value);
				} catch (final MissingResourceException e) {
					logger.error("Can't find key " + key + " in bundle " + bundleValue);
				}
			}
		}
	}

	/**
	 * Initialise les messages I18N du package spécifié.
	 *
	 * @param packageName Le nom du package de base à initialiser.
	 */
	public static void initializePackage(final String packageName) {
		if (logger.isTraceEnabled()) logger.trace("initializePackage(" + packageName + ")");

		//packageName = packageName.replace(PACKAGE_SEP, FILE_SEP);
		final ClassLoader classLoader = I18N.class.getClassLoader();
		final URL parentURL = classLoader.getResource(packageName);
		if (parentURL == null) {
			throw new IllegalArgumentException("Package " + packageName + " not found.");
		}
		if (logger.isDebugEnabled()) logger.debug("parentURL : " + parentURL.toString());

		// Gestion suivant le type de protocole
		final Protocol protocol = Protocol.valueOf(parentURL.getProtocol().toUpperCase());
		switch (protocol) {
			// Fichiers
			case FILE:
				try {
					final File file = new File(parentURL.toURI());
					if (logger.isDebugEnabled()) logger.debug("file : " + file);
					// Initialisation des dossiers de package et fichiers class en mode récursif
					if (file.isDirectory()) {
						for (final File child : file.listFiles()) {
							initializePackage(packageName + FILE_SEP + child.getName());
						}
					} else if (file.isFile()) {
						if (file.getName().endsWith(CLASS_EXT)) {
							if (logger.isTraceEnabled()) logger.trace("I18N initialization for " + packageName);
							String className = packageName.replace(FILE_SEP, PACKAGE_SEP);
							className = className.substring(0, className.lastIndexOf(CLASS_EXT));
							final Class<?> clazz = Class.forName(className);
							initializeObject(clazz);
						}
					} else {
						logger.warn("File " + file.getAbsolutePath() + " is neither a directory nor a file.");
					}
				} catch (final URISyntaxException e) {
					// Ne peut pas se produire
					logger.error(e);
					throw new RuntimeException(e);
				} catch (final ClassNotFoundException e) {
					// Ne peut pas se produire
					logger.error(e);
					throw new RuntimeException(e);
				}
				break;
			// Jars
			case JAR:
				try {
					final JarURLConnection jarUrlConnection = (JarURLConnection)parentURL.openConnection();
					final JarFile jar = jarUrlConnection.getJarFile();
					for (final Enumeration<JarEntry> entries = jar.entries(); entries.hasMoreElements();) {
						final JarEntry entry = entries.nextElement();
						String entryName = entry.getName();
						if (entryName.endsWith(CLASS_EXT) && StringUtils.startsWith(entryName, packageName)) {
							if (logger.isTraceEnabled()) logger.trace("I18N initialization for " + entryName);
							entryName = entryName.replace(FILE_SEP, PACKAGE_SEP);
							entryName = entryName.substring(0, entryName.lastIndexOf(CLASS_EXT));
							final Class<?> clazz = Class.forName(entryName);
							initializeObject(clazz);
						}
					}
				} catch (final Exception e) {
					logger.error(e);
					throw new RuntimeException(e);
				}
				break;
			default:
				throw new IllegalArgumentException("Unsupported protocol : " + protocol);
		}
	}

}
